import OpenGL.GL as gl
import numpy as np
import glm
import pygl

class ScreenQuad:
    def __init__(self, tex:pygl.RenderTexture2D, fullscreen=True, x=-1.0, 
                 y=1.0, width=2.0, height=2.0) -> None:
        self.program = pygl.ProgramVF("common/shaders/quad.vs", 
                                      "common/shaders/quad.fs")
        self.vertices = np.array([
            # 位置           纹理
            x + width, y - height, 0.0, 1.0, 0.0,
            x + width, y, 0.0, 1.0, 1.0,
            x, y, 0.0, 0.0, 1.0,
            x, y - height, 0.0, 0.0, 0.0
        ], dtype=gl.GLfloat)
        self.indices = np.array([
            0, 1, 2, 2, 3, 0
        ], dtype=gl.GLuint)
        self.vao = pygl.VertexArrayObject()
        self.vbo = pygl.VertexBufferObject(self.vertices)
        self.ebo = pygl.ElementBufferObject(self.indices)
        binding_point = 0
        self.vao.setVertexBuffer(self.vbo, binding_point, 0, 
                                 5 * gl.sizeof(gl.GLfloat))
        self.vao.setElementBuffer(self.ebo)
        attribute_position = pygl.VertexAttribute("position", 0, 3, 
                                                  gl.GL_FLOAT, False, 0)
        attribute_tex_coord = pygl.VertexAttribute("tex_coord",1, 2, 
                        gl.GL_FLOAT, False, 3 * gl.sizeof(gl.GLfloat))
        self.vao.setVertexAttribute(binding_point, attribute_position)
        self.vao.setVertexAttribute(binding_point, attribute_tex_coord)
        self.model_matrix = glm.mat4(1.0)
        self.fullscreen = fullscreen
        self.tex = tex
        self.rotation = glm.vec3(0.0, 0.0, 0.0)
        self.position = glm.vec3(0.0, 0.0, 0.0)
        self.scale = glm.vec3(1.0, 1.0, 1.0)
        self.updateModelMatrix()

    def render(self, view_matrix: glm.mat4, projection_matrix: glm.mat4) -> None:
        self.program.use()
        self.vao.bind()
        if self.fullscreen:
            self.program.setUniform1i(0, 0)
        else:
            self.program.setUniform1i(0, 1)
            self.program.setUniformMatrix4fv(1, self.model_matrix)
            self.program.setUniformMatrix4fv(2, view_matrix)
            self.program.setUniformMatrix4fv(3, projection_matrix)
        self.tex.bind(0)
        gl.glDrawElements(gl.GL_TRIANGLES, len(self.indices) ,gl.GL_UNSIGNED_INT, None)
        self.tex.unbind(0)

    def delete(self)->None:
        self.vao.delete()
        self.vbo.delete()
        self.ebo.delete()
        self.program.delete()

    def updateModelMatrix(self)->None:
        scale_matrix = glm.scale(glm.mat4(1.0), self.scale)
        rotation_matrix = glm.rotate(glm.mat4(1.0), glm.radians(self.rotation.x), 
                                     glm.vec3(1.0, 0.0, 0.0))
        rotation_matrix = glm.rotate(rotation_matrix, 
                        glm.radians(self.rotation.y), glm.vec3(0.0, 1.0, 0.0))
        rotation_matrix = glm.rotate(rotation_matrix, 
                        glm.radians(self.rotation.z), glm.vec3(0.0, 0.0, 1.0))
        translation_matrix = glm.translate(self.position)
        self.model_matrix = translation_matrix * rotation_matrix * scale_matrix
